package com.hison.tandainbao.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.RandomUtil;
import com.aliyuncs.exceptions.ClientException;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hison.tandainbao.entiy.pojo.domain.TbUserInfo;
import com.hison.tandainbao.entiy.pojo.domain.User;
import com.hison.tandainbao.entiy.pojo.dto.*;
import com.hison.tandainbao.response.ResponseResult;
import com.hison.tandainbao.service.TbUserInfoService;
import com.hison.tandainbao.service.UserService;
import com.hison.tandainbao.mapper.UserMapper;
import com.hison.tandainbao.util.JWTUtils;
import com.hison.tandainbao.util.RegexUtils;
import com.hison.tandainbao.util.UserHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.BitFieldSubCommands;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;

import static com.hison.tandainbao.util.SMSUtils.sendSms;

/**
 * @author hison
 * @description 针对表【tb_user】的数据库操作Service实现
 * @createDate 2024-01-24 22:14:49
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements UserService {


    @Autowired
    private UserMapper userMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 登录
     *
     * @param login
     * @return 成功信息   token
     */
    @Override
    public ResponseResult login(LoginDto login) {
        //验证用户名 电话号码是否为空
        if (login.getName().trim() == null || login.getName().trim() == "") {
            return ResponseResult.error("账号不能为空");
        }
        if (login.getPassword().trim() == null || login.getPassword().trim() == "") {
            return ResponseResult.error("密码不能为空");
        }
        //验证用户是否存在
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("name", login.getName().trim());
        wrapper.eq("password", login.getPassword().trim());
        User user = userMapper.selectOne(wrapper);
        // 生成token
        String token = JWTUtils.geneJsonWebToken(user);

        //将user对象转为userDto对象
        UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);
        //将对象转为map集合
        Map<String, Object> userMap = BeanUtil.beanToMap(userDTO, new HashMap<>(),
                //设置忽略空值
                CopyOptions.create().setIgnoreNullValue(true)
                        //将字段的值转为string类型
                        .setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));
        String tokenKey = "login:token" + token;
        //7.3存储
        redisTemplate.opsForHash().putAll(tokenKey, userMap);
        //设置token有效期  30分钟   session过期时间
        redisTemplate.expire(tokenKey, 30L, TimeUnit.MINUTES);

//        // 将生成的token保存到redis
//        redisTemplate.opsForValue().set("login:token", token);

        //将登录信息返回到前端
        return ResponseResult.ok("登录成功", token);
    }


    /**
     * 随机生成头像
     */
    private static final String[] headImg = {
            "https://xd-video-pc-img.oss-cn-beijing.aliyuncs.com/xdclass_pro/default/head_img/12.jpeg",
            "https://xd-video-pc-img.oss-cn-beijing.aliyuncs.com/xdclass_pro/default/head_img/11.jpeg",
            "https://xd-video-pc-img.oss-cn-beijing.aliyuncs.com/xdclass_pro/default/head_img/13.jpeg",
            "https://xd-video-pc-img.oss-cn-beijing.aliyuncs.com/xdclass_pro/default/head_img/14.jpeg",
            "https://xd-video-pc-img.oss-cn-beijing.aliyuncs.com/xdclass_pro/default/head_img/15.jpeg"
    };
    /**
     * 放在cdn上的随机头像
     *
     * @return
     */
    private String getRandImg() {
        int size = headImg.length;
        Random random = new Random();
        int index = random.nextInt(size);
        return headImg[index];

    }

    /**
     * 随机生成名字
     */
    public static String generateRandomString() {
        String characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        StringBuilder stringBuilder = new StringBuilder();

        Random random = new Random();
        for (int i = 0; i < 8; i++) {
            int index = random.nextInt(characters.length());
            char randomChar = characters.charAt(index);
            stringBuilder.append(randomChar);
        }

        return stringBuilder.toString();
    }
    /**
     * 用户注册接口
     *
     * @param signupDto
     * @return
     */
    @Override
    public ResponseResult signup(SignupDto signupDto) {
        //判断电话是否为空
        if (signupDto.getPhone() == null || signupDto.getPhone().trim().equals("")) {
            return ResponseResult.error("电话号码不能拿为空");
        }
        //判断姓名是否为空
        if (signupDto.getName() == null || signupDto.getName().trim().equals("")) {
            return ResponseResult.error("用户名不能为空");
        }
         //将对象封装
        //设置昵称
        signupDto.setNickName(generateRandomString());
        //设置头像
        signupDto.setUserIcon(getRandImg());
        User user = new User();
        BeanUtils.copyProperties(signupDto, user);
        //保存用户信息
        int insert = userMapper.insert(user);
        return insert == 0 ? ResponseResult.error("注册失败") : ResponseResult.ok("注册成功");
    }

    @Override
    public ResponseResult edit(UpdateUser updateUser) {
        //判断是否存在该用户
        User user = userMapper.selectById(updateUser.getId());
        if (user == null) {
            return ResponseResult.error("当前用户不存在");
        }
        int insert = userMapper.updateById(updateUser);
        return insert == 0 ? ResponseResult.error("更新失败") : ResponseResult.ok("更新成功");
    }

    public ResponseResult senCode(String  phone) {
        //根据所提供的手机号码 获取验证码 并通过短信发送
        String code = RandomUtil.randomNumbers(6); //生成随机6位数
        //4.保存验证码到redis    设置过期时间2分钟
        redisTemplate.opsForValue().set("LOGIN:CODE:KEY" + phone, code, 2L, TimeUnit.MINUTES);
        //5.发送验证码   需要调用第三方平台
        log.debug("发送短信验证码成功,验证码{}", code);
        try {
            sendSms(phone,code);
        } catch (ClientException e) {
            throw new RuntimeException(e);
        }
        return   ResponseResult.ok("验证码发送成功");
    }


    @Override
    public ResponseResult reset(ResetPassword  resetPassword) {
        //验证电话号码是否符合规范
        boolean phoneInvalid = RegexUtils.isPhoneInvalid(resetPassword.getPhone());
        if (phoneInvalid){
            return  ResponseResult.error("电话号码有误，请重新输入");
        }
        //先根据ID和电话查找用户是否存在
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        if (resetPassword.getId() != null || !"".equals(resetPassword.getId())) {
            wrapper.eq("id", resetPassword.getId());
        }
        if (resetPassword.getPhone() != null || !"".equals(resetPassword.getPhone())) {
            wrapper.eq("phone", resetPassword.getPhone());
        }
        User user = userMapper.selectOne(wrapper);
        if (user == null ){
            return  ResponseResult.error("用户不存在");
        }

        //从redis中取出验证码，判断验证码是否正确
        //2.校验验证码
        String code = resetPassword.getCode();  //登录的时候传入的验证码
        //从redis中取出并校验
        String cacheCode = redisTemplate.opsForValue().get("LOGIN:CODE:KEY" + resetPassword.getPhone());
        if (cacheCode == null || !cacheCode.equals(code)) {
            //3.不一致，报错
            return ResponseResult.error("验证码有误");
        }
        //一致则重置密码  将密码格式化
        return ResponseResult.ok("密码格式化成功");
    }

    @Override
    public ResponseResult logOut(String token) {
        //TODO 删除Redis中的登录信息
        redisTemplate.delete("login:token" + token);
        return ResponseResult.ok("退出成功");
    }


    @Override
    public ResponseResult sign() {
        //1.获取当前登录用户
     //   Long userId = UserHolder.getUser().getId();
        //2.获取日期
        LocalDateTime now = LocalDateTime.now();
        //3.拼接key   当前年月
        String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
      //  String key = USER_SIGN_KEY + userId + keySuffix;
        //4.获取今天是本月的第几天
        int dayOfMonth = now.getDayOfMonth();
        //5. 写入redis   setBIT   key   offset   1    从0开始数所以要减一
     //   stringRedisTemplate.opsForValue().setBit(key, dayOfMonth - 1, true);
        return ResponseResult.ok();
    }

    @Override
    public ResponseResult signCount() {
        //1.获取当前登录用户
        //  Long userId = UserHolder.getUser().getId();
        //2.获取日期
        LocalDateTime now = LocalDateTime.now();
        //3.拼接key
        String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
        //   String key = USER_SIGN_KEY + userId + keySuffix;
        //4.获取今天是本月的第几天
        int dayOfMonth = now.getDayOfMonth();
        //5.获取本月截止今天为止的所有签到记录,返回的是一个十进制数字
        //   List<Long> result = stringRedisTemplate.opsForValue().bitField(key,BitFieldSubCommands.create()         .get(BitFieldSubCommands.BitFieldType.signed(dayOfMonth)).valueAt(0));
//        if (result == null || result.isEmpty()) {
//            //没有任何签到记录
//            return ResponseResult.ok(0);
//        }
//        Long num = result.get(0);
//        if (num == null || num == 0) {
//            return ResponseResult.ok(0);
//        }
        //6.循环遍历
        int count = 0;
        while (true) {
            //7.让数字与1做与运算，得到数字的最后一个bit位
            //判断这个bit位是否为0
//            if ((num & 1) == 0){
//                //如果为0  说明未签到   结束
//                break;
//            }else {
//                //如果不为0  说明已签到   计数器加一
//                count++;
//            }
//            //把数字又移一位，抛弃最后一个bit位，继续下一位
//            num >>>= 1;
//        }
            return ResponseResult.ok(count);
        }


    }




    /**
     * 用户详细信息服务类
     */
    @Autowired
    private TbUserInfoService tbUserInfoService;

    //查询用户详细信息
    @Override
    public ResponseResult getAllInfo(Long id) {
        //根据用户id 查询出用户详细信息
        TbUserInfo allInfo = tbUserInfoService.getAllInfo(id);
        //根据id查询出用户的基本信息
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("id", id);
        User user = userMapper.selectOne(wrapper);

        //对查询出来的结果进行封装
        UserInfo userInfo = new UserInfo();
        userInfo.setId(user.getId());
        userInfo.setName(user.getName());
        userInfo.setEmail(allInfo.getEmail());
        userInfo.setBirthday(allInfo.getBirthday());
        userInfo.setCredits(allInfo.getCredits());
        userInfo.setNickName(user.getNickName());
        userInfo.setCity(allInfo.getCity());
        userInfo.setFans(allInfo.getFans());
        userInfo.setUserIcon(user.getUserIcon());
        userInfo.setCredits(allInfo.getCredits());
        userInfo.setDescription(allInfo.getDescription());
        return ResponseResult.ok(userInfo);
    }

    @Override
    public ResponseResult follow(Integer userId) {
        Long id = UserHolder.getUser().getId();
        int i = userMapper.follow(userId,id);
        if(i< 1){
            return ResponseResult.error("关注失败");
        }
        return ResponseResult.ok("关注成功");
    }


    /**
     * 管理员登录
     *
     * @param phone    电话
     * @param password 密码
     * @return @return {@code ResponseResult }
     * @author $USER$
     * @date 2024/04/07
     * @see String
     * @see String
     * @see ResponseResult
     * @since version
     */
    @Override
    public ResponseResult adminLogin(String phone, String password) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("phone", phone);
        wrapper.eq("password", password);
        wrapper.eq("name", "admin");
        User user = userMapper.selectOne(wrapper);
        if (user != null){
            // 生成token
            String token = JWTUtils.geneJsonWebToken(user);

            //将user对象转为userDto对象
            UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);
            //将对象转为map集合
            Map<String, Object> userMap = BeanUtil.beanToMap(userDTO, new HashMap<>(),
                    //设置忽略空值
                    CopyOptions.create().setIgnoreNullValue(true)
                            //将字段的值转为string类型
                            .setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));
            String tokenKey = "login:token" + token;
            //7.3存储
            redisTemplate.opsForHash().putAll(tokenKey, userMap);
            //设置token有效期  30分钟   session过期时间
            redisTemplate.expire(tokenKey, 30L, TimeUnit.MINUTES);

//        // 将生成的token保存到redis
//        redisTemplate.opsForValue().set("login:token", token);

            //将登录信息返回到前端
            return ResponseResult.ok("登录成功", token);
        }
        return ResponseResult.error("登录失败");
    }

    @Override
    public ResponseResult AdminOutLogin() {
        //删除ThreadLocal中的值
        UserHolder.removeUser();
        //删除redis中的token信息
        return ResponseResult.ok();
    }


}




